home *** CD-ROM | disk | FTP | other *** search
- /* Display a list of help topics next to help text. The user can choose
- a topic from the list. The list and text can both used styled text.
- The list of topics are contained, one per line, in the resources with
- id RLHELP_TOPICS of type RES_TEXT_TYPE and RES_STYL_TYPE. The text
- for each topic is contained in resources of type RES_TEXT_TYPE and
- RES_STYL_TYPE with the same name as the topic (so GetNamedResource
- can be used to load the text corresponding to the topic).
-
- 94/01/12 aih
- - overrides list's within handler, rather than relying on the order
- in which event handlers are executed
-
- 93/12/16 aih
- - window's position is saved in prefs file
-
- 93/11/17 aih
- - added resize function to minimize drawing drawn on resizing list
-
- 93/03/17 AIH
- - Topic is updated on null events
-
- 93/03/10 AIH
- - The window's minimum and maximum size are set to fix a problem with
- zooming the window
-
- 93/03/06 AIH
- - Up and down arrow keys scroll can be used to select topics
- - All help windows are closed when memory is low
- - Menu commands are disabled if memory is low
-
- 93/03/03 Ari Halberstadt (AIH)
- - Created */
-
- #include <ctype.h>
- #include <limits.h>
- #include <string.h>
- #include "DialogLib.h"
- #include "DrawLib.h"
- #include "EventLib.h"
- #include "HelpLib.h"
- #include "KeyLib.h"
- #include "ListLib.h"
- #include "MathLib.h"
- #include "MemoryLib.h"
- #include "PreferencesLib.h"
- #include "RectangleLib.h"
- #include "ResourceConstantsLib.h"
- #include "ResourceLib.h"
- #include "ResourceTypeLib.h"
- #include "TextIOLib.h"
- #include "WindowLib.h"
-
- /* items in the help dialog */
- enum {
- iListUser = 1,
- iTextUser
- };
-
- static HelpHandle gHelp;
-
- /* true if the help window is valid */
- Boolean HelpValid(HelpHandle help)
- {
- return(HandleValidSize(help, sizeof(HelpType)));
- }
-
- /* true if the help window topic is valid */
- Boolean HelpTopicValid(HelpHandle help, HelpTopicType topic)
- {
- Rect bounds;
- ListDataBounds((**help).list, &bounds);
- return((bounds.top == bounds.bottom && topic == bounds.top) ||
- (bounds.top <= topic && topic < bounds.bottom));
- }
-
- /* read the list of topics */
- static void HelpReadList(HelpHandle help)
- {
- Str255 str;
- Cell cell;
- short n = 0;
-
- require(HelpValid(help));
- n = *(short *) *ResGet('STR#', RLS_HELP);
- LDoDraw(false, (**help).list);
- LAddRow(n, 0, (**help).list);
- for (cell.h = cell.v = 0; cell.v < n; cell.v++) {
- GetIndString(str, RLS_HELP, cell.v + 1);
- LSetCell(str + 1, *str, cell, (**help).list);
- }
- LDoDraw(true, (**help).list);
- ensure(HelpValid(help));
- }
-
- /* Read the help corresponding to the indexed topic. A missing style
- resource does not prevent the help system from working. */
- static void HelpReadText(HelpHandle help, HelpTopicType topic)
- {
- volatile TextHandle text = NULL; /* the text record */
- Handle rsrc = NULL;/* handle to the text resource */
- short id = 0; /* id of the resource */
- OSType type = 0; /* type of the resource */
- Str255 dummy; /* name of resource (name of topic as Pascal string) */
- Cell cell; /* cell containing topic name */
- CStr255 name; /* name of topic to load */
- short len = 0; /* length of topic name */
-
- require(HelpValid(help));
- require(HelpTopicValid(help, topic));
- TRY {
- len = sizeof(name)-1; cell.h = 0; cell.v = topic;
- LGetCell(name, &len, cell, (**help).list);
- name[len] = 0;
- text = TxScrlText((**help).text);
- rsrc = ResGetNamed(RES_HELP_TYPE, name);
- GetResInfo(rsrc, &id, &type, dummy);
- FailResError();
- TxReadTextRes(text, RES_HELP_TYPE, id);
- if (ResExists('styl', id))
- TxReadStyl(text, id);
- TxInval(text);
- TxSelect(text, 0, 0);
- TxScrlChanged((**help).text);
- } CATCH {
- if (text) {
- TxSelect(text, 0, TxLength(text));
- TxDelete(text);
- TxScrlChanged((**help).text);
- }
- } ENDTRY;
- ensure(HelpValid(help));
- }
-
- /* begin use of a help window */
- HelpHandle HelpBegin(void)
- {
- static EventTableType overrideTable; /* for overriding list's within handler */
- volatile HelpHandle help = NULL; /* the new help structure */
- TextScrollHandle text = NULL; /* field for displaying help text */
- ListHandle list = NULL; /* displays list of help topics */
- DialogPtr dlg = NULL; /* dialog containing help */
- Rect lbounds; /* list's data bounds */
- Cell lsize; /* size of list's cells */
- Rect box; /* for setting bounds of list and text */
-
- TRY {
-
- /* create dialog */
- help = HandleBeginClear(sizeof(HelpType));
- dlg = DlgBegin(RLD_HELP);
- (**help).dlg = dlg;
- DlgCenter(dlg);
-
- /* create text */
- DlgBox(dlg, iTextUser, &box);
- text = TxScrlBegin(dlg, &box, true, true, false, false,
- TX_UNSTYLED_KIND, NULL);
- (**help).text = text;
- TxMarginSet(TxScrlText(text), 0);
- TxWrapSet(TxScrlText(text), true);
- TxFlagsSet(TxScrlText(text),
- TxFlags(TxScrlText(text)) | TX_READ_ONLY | TX_WRAP_TO_VIEW);
-
- /* create list */
- SetPt(&lsize, 0, 0);
- SetRect(&lbounds, 0, 0, 1, 0);
- DlgBox(dlg, iListUser, &box);
- list = ListBegin(&box, &lbounds, lsize, 0, dlg,
- true, false, false, true, true);
- (**help).list = list;
- (**list).selFlags = lOnlyOne;
- FrameFlagsSet(ListFrame(list), FrameFlags(ListFrame(list)) & ~FRAME_ANCHOR_RIGHT);
-
- /* replace list's within handler so it isn't called, which allows
- us to catch the mouse down events in the list and make it look
- like they were clicks in the help object */
- overrideTable = *WinObjectTable(dlg, list);
- overrideTable.focusWindow.within = NULL;
- WinObjectTableSet(dlg, list, &overrideTable);
-
- /* read help */
- HelpReadList(help);
- HelpTopicSet(help, 0);
-
- /* finish setting up window */
- WinRegister(dlg, help, HelpEventTable());
- WinTabUnregister(dlg, list);
- WinTabRegister(dlg, help);
- WinFocusSet(dlg, help);
- WinZoomRestore(dlg, PrefsFile(), PREFS_HELP_POSITION);
- WinShow(dlg);
-
- } CATCH {
- HelpEnd(help);
- } ENDTRY;
- ensure(HelpValid(help));
- return(help);
- }
-
- /* end use of the help window */
- void HelpEnd(HelpHandle help)
- {
- if (help) {
- WinTabUnregister((**help).dlg, help);
- WinUnregister((**help).dlg, help);
- TxScrlEnd((**help).text);
- ListEnd((**help).list);
- DlgEnd((**help).dlg);
- HandleEnd(help);
- help = NULL;
- }
- ensure(! HelpValid(help));
- }
-
- /* return the index to the topic displayed in the help */
- HelpTopicType HelpTopic(HelpHandle help)
- {
- require(HelpValid(help));
- return((**help).topic);
- }
-
- /* set the topic displayed in the help window */
- void HelpTopicSet(HelpHandle help, short topic)
- {
- Cell cell;
- Boolean sel = false;
-
- require(HelpValid(help));
- require(HelpTopicValid(help, topic));
- (**help).topic = (**help).newtopic = topic;
- cell.h = 0; cell.v = topic;
- ListSelectOne((**help).list, cell);
- LAutoScroll((**help).list);
- HelpReadText(help, topic);
- ensure(HelpValid(help));
- }
-
- /* true if the point is within the topic list */
- Boolean HelpWithin(HelpHandle help, Point where)
- {
- require(HelpValid(help));
- return(ListWithin((**help).list, where));
- }
-
- /* set input focus */
- void HelpFocus(HelpHandle help, Boolean focus)
- {
- ListFocus((**help).list, focus);
- }
-
- /* update topic */
- void HelpIdle(HelpHandle help)
- {
- require(HelpValid(help));
- if ((**help).newtopic != (**help).topic)
- HelpTopicSet(help, (**help).newtopic);
- }
-
- /* return sleep period */
- TicksType HelpAdjustSleep(HelpHandle help)
- {
- return(help && (**help).newtopic != (**help).topic ? 0 : LONG_MAX);
- }
-
- /* select a topic if it's an arrow key */
- void HelpKeyDown(HelpHandle help, EventRecord *event)
- {
- Cell cell;
-
- require(HelpValid(help));
- ListKeyDown((**help).list, event);
- cell.h = cell.v = 0;
- if (LGetSelect(true, &cell, (**help).list))
- (**help).newtopic = cell.v;
- ensure(HelpValid(help));
- }
-
- /* select a topic */
- void HelpMouseDown(HelpHandle help, EventRecord *event)
- {
- Cell cell;
-
- require(HelpValid(help));
- ListMouseDown((**help).list, event);
- cell.h = cell.v = 0;
- if (LGetSelect(true, &cell, (**help).list))
- (**help).newtopic = cell.v;
- ensure(HelpValid(help));
- }
-
- /* true if help has the focus */
- static Boolean HelpHasFocus(void)
- {
- return(gHelp && WinHasFocus((**gHelp).dlg));
- }
-
- /* enable the help menu item if the help window isn't the front window */
- void HelpAdjustMenu(void)
- {
- if (MemWarning() < MEM_WARNING_VERY_LOW) {
- if (! WinModalHasFocus()) MenuCmdEnable(CMD_HELP);
- MenuCmdCheck(CMD_HELP, HelpHasFocus());
- }
- if (HelpHasFocus())
- MenuCmdEnable(CMD_CLOSE);
- }
-
- /* open or select the main help window */
- void HelpOpen(void)
- {
- if (gHelp)
- WinSelect((**gHelp).dlg);
- else
- gHelp = HelpBegin();
- }
-
- /* close the main help window */
- void HelpClose(void)
- {
- if (gHelp) {
- if ((**gHelp).dlg)
- WinZoomSave((**gHelp).dlg, PrefsFile(), PREFS_HELP_POSITION);
- HelpEnd(gHelp);
- gHelp = NULL;
- }
- }
-
- /* handle the help menu command */
- Boolean HelpMenu(const MenuPickType *pick)
- {
- Boolean handled = false;
-
- switch (pick->cmd) {
- case CMD_HELP:
- HelpOpen();
- handled = true;
- break;
- case CMD_CLOSE:
- if (HelpHasFocus()) {
- HelpClose();
- handled = true;
- }
- break;
- }
- return(handled);
- }
-
- /* handle a low memory situation */
- void HelpMemoryLow(void)
- {
- if (gHelp && MemWarning() >= MEM_WARNING_VERY_LOW)
- HelpClose();
- }
-